from maix import camera, display, image, nn, app, pinmap, time, uart, touchscreen, thread
import socket, threading
'''
协议
检测到最开始的目标药房号：0x0a 0x0b 0x01 target 0x0c
在路上检测到的目标药房号：0x0a 0x0b 0x02 (0x00:L、0x01:R) 0x0c
识别到停车点：           0x0a 0x0b 0x03 0x00 0x0c
'''
# 初始化串口
device = "/dev/ttyS0"
serial0 = uart.UART(device, 115200)
# 加载模型
detector = nn.YOLOv5(model="/root/models/model-120311(number)/model_120311.mud", dual_buff=True)
# 打开摄像头并显示
cam = camera.Camera(680, 480, detector.input_format())
dis = display.Display()
# 初始化按键扫描对象
ts = touchscreen.TouchScreen()
X_btn_pos = [620, 0, 60, 60]
X_btn_disp_pos = image.resize_map_pos(cam.width(), cam.height(), dis.width(), dis.height(), image.Fit.FIT_CONTAIN, X_btn_pos[0], X_btn_pos[1], X_btn_pos[2], X_btn_pos[3])

Switch_btn_pos = [620, 100, 60, 60]
Switch_btn_disp_pos = image.resize_map_pos(cam.width(), cam.height(), dis.width(), dis.height(), image.Fit.FIT_CONTAIN, Switch_btn_pos[0], Switch_btn_pos[1], Switch_btn_pos[2], Switch_btn_pos[3])

JIAN_btn_pos = [620, 420, 60, 60]
JIAN_btn_disp_pos = image.resize_map_pos(cam.width(), cam.height(), dis.width(), dis.height(), image.Fit.FIT_CONTAIN, JIAN_btn_pos[0], JIAN_btn_pos[1], JIAN_btn_pos[2], JIAN_btn_pos[3])
JIA_btn_pos = [560, 420, 60, 60]
JIA_btn_disp_pos = image.resize_map_pos(cam.width(), cam.height(), dis.width(), dis.height(), image.Fit.FIT_CONTAIN, JIA_btn_pos[0], JIA_btn_pos[1], JIA_btn_pos[2], JIA_btn_pos[3])

FilterJia_btn_pos = [0,420,60,60]
FilterJia_btn_disp_pos = image.resize_map_pos(cam.width(), cam.height(), dis.width(), dis.height(), image.Fit.FIT_CONTAIN, FilterJia_btn_pos[0], FilterJia_btn_pos[1], FilterJia_btn_pos[2], FilterJia_btn_pos[3])
FilterJian_btn_pos = [60,420,60,60]
FilterJian_btn_disp_pos = image.resize_map_pos(cam.width(), cam.height(), dis.width(), dis.height(), image.Fit.FIT_CONTAIN, FilterJian_btn_pos[0], FilterJian_btn_pos[1], FilterJian_btn_pos[2], FilterJian_btn_pos[3])

#************************************************************
# Thread变量
Stop_thread = list(range(3))    # 第0位用于控制识别任务是否开启(其他两位预留)
#************************************************************
Start_find_blob = 0         # 开始识别色块标志位
delay_flag = 0
t = 0
s = 0
target = 0                  # 目标药房
L = 0                       # 左转向
R = 1                       # 右转向
direction = 2               # 转向标志
MAXcount = 10               # 滤波宏
MINcount = 5            
Filter_flag = 0
MAX_road_count = 1          # 滤波宏
MIN_road_count = 1            
max_count = MAXcount        # 滤波系数
min_count = MINcount
count = 0           # 统计计数
stop_flag = 0       # 停车标志
blobs_quantity = 0  # 记录块的数量
blobs_max = 4       # 最多出现色块数量
number_list = list(range(max_count))                # 保存每次识别的结果
tinydict = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0} # 保存每个数字对应的出现次数
number_name = [' one',' two',' three',' four',' five','six',' seven',' eight']
#************************************************************

# 等待线程
def Wait_thread(flag, delay_ms):
    global Stop_thread
    Stop_thread[flag] = 1
    time.sleep_ms(3000)
    Stop_thread[flag] = 0

# 显示屏显示数据
def display_data(img):
    global target,direction,L,R,blobs_quantity,stop_flag,Filter_flag
    inteval = 24
    # 显示参数
    img.draw_string(0,8,"TAR:{}".format(target),color = image.COLOR_RED,scale=4,thickness=3)
    if direction == L:
        img.draw_string(0,58*1,"DIR:L",color = image.COLOR_BLUE,scale=4,thickness=3)
    elif direction == R:
        img.draw_string(0,58*1,"DIR:R",color = image.COLOR_BLUE,scale=4,thickness=3)
    else:
        img.draw_string(0,58*1,"DIR:",color = image.COLOR_BLUE,scale=4,thickness=3)
    img.draw_string(0,inteval*2+58,"blobs:{}".format(blobs_quantity),color = image.COLOR_GREEN,scale=2)
    img.draw_string(0,inteval*3+58,"blobs_M:{}".format(blobs_max),color = image.COLOR_GREEN,scale=2)
    img.draw_string(0,inteval*4+58,"Max_c:{}".format(max_count),color = image.COLOR_BLUE,scale=2)
    img.draw_string(0,inteval*5+58,"Min_c:{}".format(min_count),color = image.COLOR_BLUE,scale=2)
    img.draw_string(0,inteval*6+58,"stop:{}".format(stop_flag),color = image.COLOR_BLUE,scale=2)
    if Filter_flag == 0:
        img.draw_string(0,inteval*7+58,"road_Max:{}".format(MAX_road_count),color = image.COLOR_RED,scale=2)
        img.draw_string(0,inteval*8+58,"road_Min:{}".format(MIN_road_count),color = image.COLOR_GREEN,scale=2)
    else:
        img.draw_string(0,inteval*7+58,"road_Max:{}".format(MAX_road_count),color = image.COLOR_GREEN,scale=2)
        img.draw_string(0,inteval*8+58,"road_Min:{}".format(MIN_road_count),color = image.COLOR_RED,scale=2)
    # 画按键
    img.draw_string(X_btn_pos[0], X_btn_pos[1]+10, "X", image.COLOR_WHITE,scale=4)
    img.draw_rect(X_btn_pos[0], X_btn_pos[1], X_btn_pos[2], X_btn_pos[3],  image.COLOR_WHITE, 2)
    img.draw_string(Switch_btn_pos[0], Switch_btn_pos[1]+10, "Q", image.COLOR_RED,scale=4)
    img.draw_rect(Switch_btn_pos[0], Switch_btn_pos[1], Switch_btn_pos[2], Switch_btn_pos[3],  image.COLOR_RED, 2)
    img.draw_string(JIA_btn_pos[0], JIA_btn_pos[1], "+", image.COLOR_WHITE,scale=4)
    img.draw_rect(JIA_btn_pos[0], JIA_btn_pos[1], JIA_btn_pos[2], JIA_btn_pos[3],  image.COLOR_WHITE, 2)
    img.draw_string(JIAN_btn_pos[0], JIAN_btn_pos[1], "-", image.COLOR_WHITE,scale=4)
    img.draw_rect(JIAN_btn_pos[0], JIAN_btn_pos[1], JIAN_btn_pos[2], JIAN_btn_pos[3],  image.COLOR_WHITE, 2)
    img.draw_string(FilterJia_btn_pos[0], FilterJia_btn_pos[1], "+", image.COLOR_WHITE,scale=4)
    img.draw_rect(FilterJia_btn_pos[0], FilterJia_btn_pos[1], FilterJia_btn_pos[2], FilterJia_btn_pos[3],  image.COLOR_RED, 2)
    img.draw_string(FilterJian_btn_pos[0], FilterJian_btn_pos[1], "-", image.COLOR_WHITE,scale=4)
    img.draw_rect(FilterJian_btn_pos[0], FilterJian_btn_pos[1], FilterJian_btn_pos[2], FilterJian_btn_pos[3],  image.COLOR_RED, 2)

# 更新参数
def Update_parament():
    global target,max_count,min_count,count,number_list,direction,stop_flag
    target = 0      
    direction = 2   
    stop_flag = 0
    count = 0
    max_count = MAXcount
    min_count = MINcount
    number_list = list(range(max_count)) 

# 按键检测
def is_in_button(x, y, btn_pos):
    return x > btn_pos[0] and x < btn_pos[0] + btn_pos[2] and y > btn_pos[1] and y < btn_pos[1] + btn_pos[3]
def Key_scan():
    global blobs_max,Start_find_blob,Filter_flag,MAX_road_count,MIN_road_count
    x, y, pressed = ts.read()
    if is_in_button(x, y, X_btn_disp_pos) and pressed == 1:
        # 系数重置
        Update_parament()
        Start_find_blob = 0
    elif is_in_button(x, y, JIA_btn_disp_pos) and pressed == 1:
        blobs_max += 1
        time.sleep_ms(100)
    elif is_in_button(x, y, JIAN_btn_disp_pos) and pressed == 1:
        blobs_max -= 1
        time.sleep_ms(100)
    elif is_in_button(x, y, FilterJia_btn_disp_pos) and pressed == 1:
        if Filter_flag == 1:
            MAX_road_count += 1
        else:
            if MAX_road_count > MIN_road_count:
                MIN_road_count += 1
        time.sleep_ms(100)
    elif is_in_button(x, y, FilterJian_btn_disp_pos) and pressed == 1:
        if Filter_flag == 1:
            if MAX_road_count > MIN_road_count:
                MAX_road_count -= 1
        else:
            MIN_road_count -= 1
        time.sleep_ms(100)
    elif is_in_button(x, y, Switch_btn_disp_pos) and pressed == 1:
        if Filter_flag == 1:
            Filter_flag = 0
        else:
            Filter_flag = 1
        time.sleep_ms(100)

# 串口发送
def Usart_send(command,freq):
    data = [0x0a,0x0b]
    for c in command:
        data.append(c)
    data.append(0x0c)
    for f in range(0,freq):
        serial0.write(bytes(data))
        #time.sleep_ms(1)
    # print(data)

# 查看停车点
stop_site = 0   # 统计识别到的停车点次数，识别到两次清除target
def detect_stop_site(img):
    global blobs_quantity,stop_flag,stop_site,Start_find_blob,Stop_thread
    if Start_find_blob != 0:
        ROI = [cam.width()//8, cam.height()//3, cam.width()//8*6, cam.height()-cam.height()//3]
        img.draw_rect(ROI[0],ROI[1],ROI[2],ROI[3], color = image.COLOR_RED)
        blobs = img.find_blobs([[0, 30, -10, 10, -15, 15]], pixels_threshold=1200,roi=ROI)
        blobs_quantity = len(blobs)
        for blob in blobs:
            # 根据面积和长宽比例判断停车点的黑色色块
            wh_proporation = blob[2]/blob[3] if blob[2] > blob[3] else blob[3]/blob[2]  # 长宽比
            ap_proporation = blob.pixels()/blob.area()                                  # 面积像素比
            if blob.area() > 20000 or blob.pixels() > 10000 or wh_proporation > 1.7 or ap_proporation < 0.4:    # 通过面积、像素值、长宽比、面积像素值比
                blobs_quantity -= 1
                # 检查使用
                # img.draw_rect(blob[0], blob[1], blob[2], blob[3], image.COLOR_RED)
                # img.draw_string(blob[0], blob[1], str(blob.area()), image.COLOR_RED,2)
                # img.draw_string(blob[0], blob[1]+15, str(blob.pixels()), image.COLOR_RED,2)
                # img.draw_string(blob[0], blob[1]+30, "{%.2f}"%(ap_proporation), image.COLOR_RED,2)
                # img.draw_string(blob[0], blob[1]+45, "{%.2f}"%(wh_proporation), image.COLOR_RED,2)
            else:
                img.draw_rect(blob[0], blob[1], blob[2], blob[3], image.COLOR_GREEN)
        if blobs_quantity >= blobs_max:  
            stop_site += 1
            stop_flag = 1
            time.sleep_ms(600)
            Usart_send([0x03,0x00],5)
            if Stop_thread[0] == 0:
                threading.Thread(target=Wait_thread,args=(0,3000)).start()  # 开始计时线程，停止扫描停车点和数字
            if stop_site >= 2:
                stop_site = 0
                Update_parament()
        else :
            stop_flag = 0
    else :
        blobs_quantity = 0
    
# 识别数字
target_id = 0   # 记录target的ID
def detector_number(img):
    global target,cam,direction,L,R,count,number_list,max_count,min_count,number_name,Start_find_blob,target_id
    if target == 0:
        objs = detector.detect(img, conf_th = 0.7, iou_th = 0.45)
    else:
        objs = detector.detect(img, conf_th = 0.4, iou_th = 0.45)
    number_lis = [] # 用于记录每帧扫到的数字
    for obj in objs:
        if target != 0:
            if obj.class_id == target_id.class_id:
                img.draw_rect(obj.x, obj.y, obj.w, obj.h, color = image.COLOR_RED)
                msg = f'{detector.labels[obj.class_id]}: {obj.score:.2f}'
                img.draw_string(obj.x, obj.y, msg, color=image.COLOR_RED, scale=2, thickness=2)
                # 在数字中找色块
                # blobs = img.find_blobs([[0, 30, -10, 10, -15, 15]], pixels_threshold=1200,roi=[obj.x, obj.y, obj.w, obj.h])
                # for blob in blobs:
                #     ap_proporation = blob.pixels()/blob.area()
                #     img.draw_rect(blob[0], blob[1], blob[2], blob[3], image.COLOR_GREEN)
                #     img.draw_string(blob[0], blob[1], "{%.2f}" % (ap_proporation), image.COLOR_RED,2)
        else:
            img.draw_rect(obj.x, obj.y, obj.w, obj.h, color = image.COLOR_RED)
            msg = f'{detector.labels[obj.class_id]}: {obj.score:.2f}'
            img.draw_string(obj.x, obj.y, msg, color=image.COLOR_RED, scale=2, thickness=2)
        number_lis.append(obj)  # 记录扫到的数字对象
    # 统计判决
    number_list[count] = number_lis
    count += 1
    if count >= max_count:
        count = 0
        Null = 0
        # 字典计算数字出现次数
        tinydict = {1:[0,0], 2:[0,0], 3:[0,0], 4:[0,0], 5:[0,0], 6:[0,0], 7:[0,0], 8:[0,0]}
        for number_l in number_list:
            for n in number_l:
                Null = 1
                number = number_name.index(detector.labels[n.class_id]) + 1
                tinydict[number][0] += 1      
                tinydict[number][1] = n   
        if Null == 0:
            return
        name = []
        for t in tinydict.keys():
            name.append([t,tinydict[t][0]])
        print(name)            
        for key in tinydict.keys():
            if tinydict[key][0] >= min_count:
                if target == 0:
                    target = key
                    target_id = tinydict[key][1]
                    Start_find_blob = 1      
                    max_count = MAX_road_count           
                    min_count = MIN_road_count
                    Usart_send([0x01,target],5)
                    threading.Thread(target=Wait_thread,args=(0,3000)).start()  # 开始计时线程，停止扫描停车点和数字
                else :
                    if key == target:
                        center = tinydict[key][1].x+tinydict[key][1].w//2
                        if center < cam.width()//2:     # L
                            direction = L
                        else:                           # R
                            direction = R
                        Usart_send([0x02,direction],1)
        number_list = list(range(max_count))            # 初始化列表

if __name__ == "__main__":
    while not app.need_exit():
        img = cam.read()
        if Stop_thread[0] == 0:
            detector_number(img)        # 识别数字
            detect_stop_site(img)       # 查找停车点
        Key_scan()                      # 按键检测
        display_data(img)               # 显示数据
        dis.show(img)
